/*
 * @Description: 
 * @Version: 1.0
 * @Autor: ziwei
 * @Date: 2021-09-26 14:22:55
 * @LastEditors: ziwei
 * @LastEditTime: 2021-09-26 14:41:38
 */
import {forEachValue} from './utils'
import { reactive } from "vue";
import { storeKey } from "./injectKey";
export default class Store {
  constructor(options) {
    //vuex3内部会常见一个vue实,但是vue4直接采用vue3提供的响应式方法 
    const store = this;
    store._state = reactive({data:options.state});// new Vue 响应式数据 会自动手机渲染模板

    //循环对象 把对象定义在getters上
    const _getters = options.getters;
    store.getters = {}
    forEachValue(_getters,function(fn,key) {
      console.log("store.gettersstore.getters",store.getters);
      Object.defineProperty(store.getters,key,{
        enumrable:true,
        get:()=>fn(store.state) //computed 很遗憾 目前在vuex3.1中不能用computed实现 如果组件销毁了会移除计算属性，vue3.2会改掉这个bug
      })
    })
    //vuex里面会有一个比较重要的api repalceState修改vue 
    //可以实现持久化 store._state.data = xxx 解决重新赋值问题（多包data的原因）

    //mutation action {add:function} {asyncAdd:function} 映射关系
    //commit('add')  dispatch('asyncAdd')

    store._mutations = Object.create(null);
    store._actions = Object.create(null);

    const _mutations = options.mutations;
    const _actions = options.actions;
    forEachValue(_mutations,(mutation,key)=>{
      console.log("storestore",store);
      store._mutations[key] = (payload)=>{//暂时只支持单个参数
        //内置状态和属性
        mutation.call(store,store.state,payload);
      }
    });
    forEachValue(_actions,(action,key)=>{//promise.all
      store._actions[key] = (payload)=>{
        //内置状态和属性
        action.call(store,store,payload);
      }
    });
  }
  
  //必须箭头函数 否则this为undefined 编译成bind方法 可以转移浏览器默认也支持
  commit = (type,payload) => {
    this._mutations[type](payload)
  }
  dispatch = (type,payload) => {
    this._actions[type](payload)
  }

  get state(){
    return this._state.data; 
  }
  install(app,injectKey){//app就是对象 createApp().use(store,my)
    //全局暴露一个变量 暴露的是store的实例
    app.provide(injectKey||storeKey,this);//会根app增加一个_provides,子组件会向上查找
    //Vue.prototype.$store = this;
    app.config.globalProperties.$store = this;//增添$store属性
  }
}
